use std::env;
use std::fs;
use std::process::exit;
use std::str::FromStr;
use pest::error::LineColLocation::Pos;
use pest::Parser;
use pest::iterators::Pair;
use pest_derive::Parser;

#[derive(Parser)]
#[grammar = "lexer.pest"]
pub struct ExpressionParser {}

pub enum Token {
    Const,
    Int,
    Void,
    If,
    Else,
    While,
    Break,
    Continue,
    Return,
    Plus,
    Minus,
    Mul,
    Div,
    Mod,
    Assign,
    Eq,
    Neq,
    Lt,
    Gt,
    Le,
    Ge,
    Not,
    And,
    Or,
    Semicolon,
    Comma,
    LParen,
    RParen,
    LBrace,
    RBrace,
    LBrackt,
    RBrackt,
    Ident(String),
    IntConst(i32),
}

fn main() {
    // 收集命令行参数
    let args: Vec<String> = env::args().collect();

    // 检查是否提供了文件名
    if args.len() < 2 {
        eprintln!("Usage: {} <filename>", args[0]);
        exit(1);
    }

    // 获取文件名
    let filename = &args[1];

    // 读取输入文件
    let input = fs::read_to_string(filename).expect("Failed to read file");

    // 词法分析
    ExpressionParser::tokenize_print(&input);
}

impl ExpressionParser {
    pub fn tokenize(input: &str) -> Vec<Token> {
        let pairs = match Self::parse(Rule::file, input) {
            Ok(pairs) => pairs,
            Err(err) => {
                if let Pos((line, _)) = err.line_col {
                    eprintln!("Error type A at Line {}: Mysterious character.", line);
                }
                return Vec::new();
            }
        };

        let mut res = Vec::new();

        for pair in pairs {
            for inner_pair in pair.into_inner() {
                if let Some(t) = Self::get_token_name(inner_pair.clone()) {
                    res.push(t);
                }
            }
        }

        res
    }

    pub fn tokenize_print(input: &str) {
        let pairs = match Self::parse(Rule::file, input) {
            Ok(pairs) => pairs,
            Err(err) => {
                if let Pos((line, _)) = err.line_col {
                    eprintln!("Error type A at Line {}: Mysterious character.", line);
                }
                return;
            }
        };

        for pair in pairs {
            for inner_pair in pair.into_inner() {
                let (name, value) = Self::get_name_and_value(inner_pair.clone());
                if !name.is_empty() {
                    eprintln!("{} {} at Line {}.", name, value, inner_pair.line_col().0);
                }
            }
        }
    }
    
    pub fn get_name_and_value(record: Pair<Rule>) -> (String, String) {
        let rule = record.as_rule();
        let rule_name = format!("{:?}", rule);
        if rule_name == "CONST" {
            ("CONST".to_string(), "const".to_string())
        } else if rule_name == "INT" {
            ("INT".to_string(), "int".to_string())
        } else if rule_name == "VOID" {
            ("VOID".to_string(), "void".to_string())
        } else if rule_name == "IF" {
            ("IF".to_string(), "if".to_string())
        } else if rule_name == "ELSE" {
            ("ELSE".to_string(), "else".to_string())
        } else if rule_name == "WHILE" {
            ("WHILE".to_string(), "while".to_string())
        } else if rule_name == "BREAK" {
            ("BREAK".to_string(), "break".to_string())
        } else if rule_name == "CONTINUE" {
            ("CONTINUE".to_string(), "continue".to_string())
        } else if rule_name == "RETURN" {
            ("RETURN".to_string(), "return".to_string())
        } else if rule_name == "PLUS" {
            ("PLUS".to_string(), "+".to_string())
        } else if rule_name == "MINUS" {
            ("MINUS".to_string(), "-".to_string())
        } else if rule_name == "MUL" {
            ("MUL".to_string(), "*".to_string())
        } else if rule_name == "DIV" {
            ("DIV".to_string(), "/".to_string())
        } else if rule_name == "MOD" {
            ("MOD".to_string(), "%".to_string())
        } else if rule_name == "ASSIGN" {
            ("ASSIGN".to_string(), "=".to_string())
        } else if rule_name == "EQ" {
            ("EQ".to_string(), "==".to_string())
        } else if rule_name == "NEQ" {
            ("NEQ".to_string(), "!=".to_string())
        } else if rule_name == "LT" {
            ("LT".to_string(), "<".to_string())
        } else if rule_name == "LE" {
            ("LE".to_string(), "<=".to_string())
        } else if rule_name == "GT" {
            ("GT".to_string(), ">".to_string())
        } else if rule_name == "GE" {
            ("GE".to_string(), ">=".to_string())
        } else if rule_name == "NOT" {
            ("NOT".to_string(), "!".to_string())
        } else if rule_name == "AND" {
            ("AND".to_string(), "&&".to_string())
        } else if rule_name == "OR" {
            ("OR".to_string(), "||".to_string())
        } else if rule_name == "L_PAREN" {
            ("L_PAREN".to_string(), "(".to_string())
        } else if rule_name == "R_PAREN" {
            ("R_PAREN".to_string(), ")".to_string())
        } else if rule_name == "L_BRACE" {
            ("L_BRACE".to_string(), "{".to_string())
        } else if rule_name == "R_BRACE" {
            ("R_BRACE".to_string(), "}".to_string())
        } else if rule_name == "L_BRACKT" {
            ("L_BRACKT".to_string(), "[".to_string())
        } else if rule_name == "R_BRACKT" {
            ("R_BRACKT".to_string(), "]".to_string())
        } else if rule_name == "COMMA" {
            ("COMMA".to_string(), ",".to_string())
        } else if rule_name == "SEMICOLON" {
            ("SEMICOLON".to_string(), ";".to_string())
        } else if rule_name == "OCT_INTEGER" {
            let value_str = record.as_str();
            let value = i32::from_str_radix(value_str, 8).unwrap_or_else(|_| {
                eprintln!("Failed to parse octal integer: {}", value_str);
                0
            });
            ("INTEGER_CONST".to_string(), value.to_string())
        } else if rule_name == "HEX_INTEGER" {
            let value_str = record.as_str();
            let value = i32::from_str_radix(&value_str[2..], 16).unwrap_or_else(|_| {
                eprintln!("Failed to parse hexadecimal integer: {}", value_str);
                0
            });
            ("INTEGER_CONST".to_string(), value.to_string())
        } else if rule_name == "DEX_INTEGER" {
            let value_str = record.as_str();
            let value = i32::from_str(value_str).unwrap_or_else(|_| {
                eprintln!("Failed to parse decimal integer: {}", value_str);
                0
            });
            ("INTEGER_CONST".to_string(), value.to_string())
        } else if rule_name == "ZERO" {
            ("INTEGER_CONST".to_string(), "0".to_string())
        } else if rule_name == "IDENT" {
            ("IDENT".to_string(), record.as_str().to_string())
        } else if rule == Rule::integer || rule == Rule::token || rule == Rule::keywords ||
                  rule == Rule::operators || rule == Rule::symbols {
            // 递归处理这些规则
            if let Some(inner) = record.into_inner().next() {
                Self::get_name_and_value(inner)
            } else {
                ("".to_string(), "".to_string())
            }
        } else {
            ("".to_string(), "".to_string())
        }
    }

    pub fn get_token_name(record: Pair<Rule>) -> Option<Token> {
        let rule = record.as_rule();

        match rule {
            Rule::CONST => { Some(Token::Const) }
            Rule::INT => { Some(Token::Int) }
            Rule::VOID => { Some(Token::Void) }
            Rule::IF => { Some(Token::If) }
            Rule::ELSE => { Some(Token::Else) }
            Rule::WHILE => { Some(Token::While) }
            Rule::BREAK => { Some(Token::Break) }
            Rule::CONTINUE => { Some(Token::Continue) }
            Rule::RETURN => { Some(Token::Return) }
            Rule::PLUS => { Some(Token::Plus) }
            Rule::MINUS => { Some(Token::Minus) }
            Rule::MUL => { Some(Token::Mul) }
            Rule::DIV => { Some(Token::Div) }
            Rule::MOD => { Some(Token::Mod) }
            Rule::ASSIGN => { Some(Token::Assign) }
            Rule::EQ => { Some(Token::Eq) }
            Rule::NEQ => { Some(Token::Neq) }
            Rule::LT => { Some(Token::Lt) }
            Rule::GT => { Some(Token::Gt) }
            Rule::LE => { Some(Token::Le) }
            Rule::GE => { Some(Token::Ge) }
            Rule::NOT => { Some(Token::Not) }
            Rule::AND => { Some(Token::And) }
            Rule::OR => { Some(Token::Or) }
            Rule::L_PAREN => { Some(Token::LParen) }
            Rule::R_PAREN => { Some(Token::RParen) }
            Rule::L_BRACE => { Some(Token::LBrace) }
            Rule::R_BRACE => { Some(Token::RBrace) }
            Rule::L_BRACKT => { Some(Token::LBrackt) }
            Rule::R_BRACKT => { Some(Token::RBrackt) }
            Rule::COMMA => { Some(Token::Comma) }
            Rule::SEMICOLON => { Some(Token::Semicolon) }
            Rule::OCT_INTEGER => { 
                let value_str = record.as_str();
                let value = i32::from_str_radix(value_str, 8).unwrap_or_else(|_| {
                    eprintln!("Failed to parse octal integer: {}", value_str);
                    0
                });
                Some(Token::IntConst(value))
            }
            Rule::HEX_INTEGER => { 
                let value_str = record.as_str();
                let value = i32::from_str_radix(&value_str[2..], 16).unwrap_or_else(|_| {
                    eprintln!("Failed to parse hexadecimal integer: {}", value_str);
                    0
                });
                Some(Token::IntConst(value))
            }
            Rule::DEX_INTEGER => { 
                let value_str = record.as_str();
                let value = i32::from_str(value_str).unwrap_or_else(|_| {
                    eprintln!("Failed to parse decimal integer: {}", value_str);
                    0
                });
                Some(Token::IntConst(value))
            }
            Rule::ZERO => { Some(Token::IntConst(0)) }
            Rule::IDENT => { Some(Token::Ident(record.as_str().to_string())) }
            Rule::integer | Rule::token | Rule::keywords | Rule::operators | Rule::symbols => {
                // 递归处理这些规则
                if let Some(inner) = record.into_inner().next() {
                    Self::get_token_name(inner)
                } else {
                    None
                }
            }
            _ => { None }
        }
    }
}